package pers.supeijin.devtools.converter.wx2vue.converter;

import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import pers.supeijin.devtools.converter.base.BaseConverter;
import pers.supeijin.devtools.converter.wx2vue.converter.template.ClassAttributeUtils;
import pers.supeijin.devtools.converter.wx2vue.converter.template.StyleAttributeUtils;
import pers.supeijin.devtools.utils.GeneralContext;

//模版转换器
public class TemplateConverter extends BaseConverter {
	public static final String BIND_EVENT_TAG = "bind:";
	public static final String VUE_BING_EVENT_TAG = "@";
	public static final String VUE_BING_ATTRIBUTE_TAG = ":";
	public static final String WX_FOR_TAG = "wx:for";
	public static final String WX_FOR_KEY_TAG = "wx:key";
	public static final String WX_FOR_ITEM_TAG = "wx:for-item";
	public static final String WX_FOR_ITEM_INDEX = "wx:for-index";
	public static final String DEFAULT_INDEX_TAG="index";
	public static final String DEFAULT_ITEM_TAG="item";
	private static HashMap<String, String> mTagMap = new HashMap<>();
	private static HashMap<String, String> mEventMap = new HashMap<>();
	private static HashMap<String, String> mConditionalAttributeMap = new HashMap<>();//条件属性
	private static HashMap<String, String> mLoopAttributeMap = new HashMap<>();//循环属性
	private static final String TEMPLATE_TAG = "<template> \t\n %s \t\n</template>";
	static {
		//标签
		mTagMap.put("view", "div");
		mTagMap.put("text", "span");
		mTagMap.put("image", "img");
		mTagMap.put("cover-image", "img");
		mTagMap.put("cover-view", "div");

		//事件属性
		mEventMap.put(BIND_EVENT_TAG, VUE_BING_EVENT_TAG);
		mEventMap.put("bindtap", "@click");
		mEventMap.put("bindlongtap", "@click");
		mEventMap.put("bindtouchcancel", "@touchcancel");
		mEventMap.put("bindtouchend", "@touchend");
		mEventMap.put("bindtouchmove", "@mousemove");
		mEventMap.put("bindtouchstart", "@touchstart");
		mEventMap.put("catchtap", "@click.stop");
		mEventMap.put("catchlongtap", "@click.stop");
		mEventMap.put("catchtouchcancel", "@touchcancel.stop");
		mEventMap.put("catchtouchend", "@touchend.stop");
		mEventMap.put("catchtouchmove", "@mousemove.stop");
		mEventMap.put("catchtouchstart", "@touchstart.stop");

		//条件属性
		mConditionalAttributeMap.put("wx:if", "v-if");
		mConditionalAttributeMap.put("wx:elif", "v-elif");
		mConditionalAttributeMap.put("wx:else", "v-else");

		//循环属性
		mLoopAttributeMap.put(WX_FOR_TAG, "v-for");
		mLoopAttributeMap.put(WX_FOR_KEY_TAG, ":key");
		mLoopAttributeMap.put(WX_FOR_ITEM_TAG, "");
		mLoopAttributeMap.put(WX_FOR_ITEM_INDEX, "");
	}

	public TemplateConverter(GeneralContext generalContext, VirtualFile wxmlFile) {
		super(generalContext,wxmlFile);
	}

	public XmlTag getTemplateTag() {
		ResourceTransfer resourceTransfer = new ResourceTransfer(mGeneralContext,mVirtualFile);
		resourceTransfer.transfer(mPsiFile);

		PsiElement[] psiElements = PsiTreeUtil.collectElements(mPsiFile, element -> element instanceof XmlTag);
		for (PsiElement element : psiElements) {
			XmlTag xmlTag = (XmlTag) element;
			replaceTagName(xmlTag);
			converterAttributes(xmlTag);
		}
		final String templateText = mPsiFile.getText();
		String formatText = String.format(TEMPLATE_TAG, templateText);
		return getXmlTag(formatText);
	}

	private void replaceTagName(XmlTag xmlTag) {
		String xmlTagName = xmlTag.getName();
		String newTagName = mTagMap.get(xmlTagName);
		if (newTagName != null) {
			xmlTag.setName(newTagName);
		}
	}

	//替换属性
	private void converterAttributes(XmlTag xmlTag) {
		converterEventAttributes(xmlTag);
		converterConditionalAttributes(xmlTag);
		converterLoopAttributes(xmlTag);
		converterBindAttributes(xmlTag);
		ClassAttributeUtils.converterClassAttributes(xmlTag);
		StyleAttributeUtils.converterStyleAttributes(xmlTag);
	}

	//转换条件语句
	private void converterConditionalAttributes(XmlTag xmlTag) {
		mConditionalAttributeMap.forEach((wKey, vKey) -> {
			XmlAttribute attribute = xmlTag.getAttribute(wKey);
			if (attribute != null) {
				if(attribute.getValue()!=null&& attribute.getValue().length()>0){
					attribute.setValue(getValueText(attribute.getValue()));
				}
				attribute.setName(vKey);
			}
		});
	}

	//转换循环（语句）属性
	private void converterLoopAttributes(XmlTag xmlTag) {
		if (xmlTag == null) {
			return;
		}
		final XmlAttribute forAttribute = xmlTag.getAttribute(WX_FOR_TAG);
        if(forAttribute!=null){
			final XmlAttribute itemAttribute = xmlTag.getAttribute(WX_FOR_ITEM_TAG);
			final XmlAttribute indexAttribute = xmlTag.getAttribute(WX_FOR_ITEM_INDEX);
			String itemValue=DEFAULT_ITEM_TAG;
			String indexValue=DEFAULT_INDEX_TAG;
			String keyAttributeValue=DEFAULT_INDEX_TAG;
			if(itemAttribute!=null){
				itemValue=itemAttribute.getValue();
				itemAttribute.delete();
			}
			if(indexAttribute!=null){
				indexValue=indexAttribute.getValue();
				indexAttribute.delete();
			}
			final XmlAttribute keyAttribute = xmlTag.getAttribute(WX_FOR_KEY_TAG);
			if(keyAttribute!=null){
				String valueText = getValueText(keyAttribute.getValue());
				if(valueText!=null && valueText.startsWith(itemValue)){
					keyAttributeValue=valueText;
				}
				keyAttribute.delete();
			}

			final String newForTag = mLoopAttributeMap.get(WX_FOR_TAG);
			String newForAttributeValue = getNewForAttributeValue(itemValue, indexValue, forAttribute.getValue());
			xmlTag.setAttribute(newForTag,newForAttributeValue);
			forAttribute.delete();

			final String newKey = mLoopAttributeMap.get(WX_FOR_KEY_TAG);
			xmlTag.setAttribute(newKey,keyAttributeValue);
		}
	}
    private String getNewForAttributeValue(String itemValue,String indexValue,String dataListValue){
		StringBuilder sb = new StringBuilder();
		sb.append("(").append(itemValue);
		if(indexValue!=null && indexValue.trim().length()>0){
			sb.append(",")
			.append(indexValue);
		}
		sb.append(") in ")
				.append(getValueText(dataListValue));
		return sb.toString();
	}
	//转换绑定属性
	private void converterBindAttributes(XmlTag xmlTag) {
		XmlAttribute[] attributes = xmlTag.getAttributes();
		for (XmlAttribute attribute : attributes) {
			String attributeValue = attribute.getValue();
			if (attributeValue != null && attributeValue.startsWith("{{") && attributeValue.endsWith("}}")) {
				String newAttributeName = VUE_BING_ATTRIBUTE_TAG + attribute.getName();
				xmlTag.setAttribute(newAttributeName, getValueText(attributeValue));
				attribute.delete();
			}
		}
	}

	private void converterEventAttributes(XmlTag xmlTag) {
		XmlAttribute[] attributes = xmlTag.getAttributes();
		//包含事件的数据
		List<XmlAttribute> xmlAttributes = Arrays.stream(attributes).filter(item -> mEventMap.get(item.getName()) != null || item.getName().startsWith(BIND_EVENT_TAG))
				.collect(Collectors.toList());
		//事件数据传递属性
		List<XmlAttribute> attributeList = Arrays.stream(attributes).filter(item -> item.getName().startsWith("data-"))
				.collect(Collectors.toList());

		String expression = getFunctionExpression(attributeList);
		for (XmlAttribute attribute : xmlAttributes) {
			String attributeName = attribute.getName();
			String attributeValue = attribute.getValue();
			if (attributeName.startsWith(BIND_EVENT_TAG)) {
				String newAttributeName = attributeName.replace(BIND_EVENT_TAG, VUE_BING_EVENT_TAG);
				xmlTag.setAttribute(newAttributeName, attributeValue + expression);
			} else {
				final String eventName = mEventMap.get(attributeName);
				xmlTag.setAttribute(eventName, attributeValue + expression);
			}
			attribute.delete();
		}
		//删除属性
		attributeList.forEach(item -> item.delete());
	}

	private String getFunctionExpression(List<XmlAttribute> attributeList) {
		if (attributeList != null && attributeList.size() > 0) {
			StringBuilder sb = new StringBuilder();
			sb.append("(");
			int appendIndex = 0;
			for (XmlAttribute attribute : attributeList) {
				if (appendIndex > 0) {
					sb.append(",");
				}
				sb.append(getValueText(attribute.getValue()));
				appendIndex++;
			}
			sb.append(")");
			return sb.toString();
		}
		return "";

	}

	private String getValueText(String attributeValue) {
		if (attributeValue != null) {
			int startIndex = attributeValue.lastIndexOf("{");
			int endIndex = attributeValue.indexOf("}");
			if (startIndex >= 0 && endIndex > startIndex) {
				return attributeValue.substring(startIndex + 1, endIndex);
			}
		}
		return attributeValue;
	}

}
